/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
var mxMarker = {
  /**
   * Class: mxMarker
   *
   * A static class that implements all markers for VML and SVG using a
   * registry. NOTE: The signatures in this class will change.
   *
   * Variable: markers
   *
   * Maps from markers names to functions to paint the markers.
   */
  markers: [],

  /**
   * Function: addMarker
   *
   * Adds a factory method that updates a given endpoint and returns a
   * function to paint the marker onto the given canvas.
   */
  addMarker: function (type, funct) {
    mxMarker.markers[type] = funct;
  },

  /**
   * Function: createMarker
   *
   * Returns a function to paint the given marker.
   */
  createMarker: function (
    canvas,
    shape,
    type,
    pe,
    unitX,
    unitY,
    size,
    source,
    sw,
    filled
  ) {
    var funct = mxMarker.markers[type];

    return funct != null
      ? funct(canvas, shape, type, pe, unitX, unitY, size, source, sw, filled)
      : null;
  },
};

/**
 * Adds the classic and block marker factory method.
 */
(function () {
  function createArrow(widthFactor) {
    widthFactor = widthFactor != null ? widthFactor : 2;

    return function (
      canvas,
      shape,
      type,
      pe,
      unitX,
      unitY,
      size,
      source,
      sw,
      filled
    ) {
      // The angle of the forward facing arrow sides against the x axis is
      // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
      // only half the strokewidth is processed ).
      var endOffsetX = unitX * sw * 1.118;
      var endOffsetY = unitY * sw * 1.118;

      unitX = unitX * (size + sw);
      unitY = unitY * (size + sw);

      var pt = pe.clone();
      pt.x -= endOffsetX;
      pt.y -= endOffsetY;

      var f =
        type != mxConstants.ARROW_CLASSIC &&
        type != mxConstants.ARROW_CLASSIC_THIN
          ? 1
          : 3 / 4;
      pe.x += -unitX * f - endOffsetX;
      pe.y += -unitY * f - endOffsetY;

      return function () {
        canvas.begin();
        canvas.moveTo(pt.x, pt.y);
        canvas.lineTo(
          pt.x - unitX - unitY / widthFactor,
          pt.y - unitY + unitX / widthFactor
        );

        if (
          type == mxConstants.ARROW_CLASSIC ||
          type == mxConstants.ARROW_CLASSIC_THIN
        ) {
          canvas.lineTo(pt.x - (unitX * 3) / 4, pt.y - (unitY * 3) / 4);
        }

        canvas.lineTo(
          pt.x + unitY / widthFactor - unitX,
          pt.y - unitY - unitX / widthFactor
        );
        canvas.close();

        if (filled) {
          canvas.fillAndStroke();
        } else {
          canvas.stroke();
        }
      };
    };
  }

  mxMarker.addMarker("classic", createArrow(2));
  mxMarker.addMarker("classicThin", createArrow(3));
  mxMarker.addMarker("block", createArrow(2));
  mxMarker.addMarker("blockThin", createArrow(3));

  function createOpenArrow(widthFactor) {
    widthFactor = widthFactor != null ? widthFactor : 2;

    return function (
      canvas,
      shape,
      type,
      pe,
      unitX,
      unitY,
      size,
      source,
      sw,
      filled
    ) {
      // The angle of the forward facing arrow sides against the x axis is
      // 26.565 degrees, 1/sin(26.565) = 2.236 / 2 = 1.118 ( / 2 allows for
      // only half the strokewidth is processed ).
      var endOffsetX = unitX * sw * 1.118;
      var endOffsetY = unitY * sw * 1.118;

      unitX = unitX * (size + sw);
      unitY = unitY * (size + sw);

      var pt = pe.clone();
      pt.x -= endOffsetX;
      pt.y -= endOffsetY;

      pe.x += -endOffsetX * 2;
      pe.y += -endOffsetY * 2;

      return function () {
        canvas.begin();
        canvas.moveTo(
          pt.x - unitX - unitY / widthFactor,
          pt.y - unitY + unitX / widthFactor
        );
        canvas.lineTo(pt.x, pt.y);
        canvas.lineTo(
          pt.x + unitY / widthFactor - unitX,
          pt.y - unitY - unitX / widthFactor
        );
        canvas.stroke();
      };
    };
  }

  mxMarker.addMarker("open", createOpenArrow(2));
  mxMarker.addMarker("openThin", createOpenArrow(3));

  mxMarker.addMarker(
    "oval",
    function (canvas, shape, type, pe, unitX, unitY, size, source, sw, filled) {
      var a = size / 2;

      var pt = pe.clone();
      pe.x -= unitX * a;
      pe.y -= unitY * a;

      return function () {
        canvas.ellipse(pt.x - a, pt.y - a, size, size);

        if (filled) {
          canvas.fillAndStroke();
        } else {
          canvas.stroke();
        }
      };
    }
  );

  function diamond(
    canvas,
    shape,
    type,
    pe,
    unitX,
    unitY,
    size,
    source,
    sw,
    filled
  ) {
    // The angle of the forward facing arrow sides against the x axis is
    // 45 degrees, 1/sin(45) = 1.4142 / 2 = 0.7071 ( / 2 allows for
    // only half the strokewidth is processed ). Or 0.9862 for thin diamond.
    // Note these values and the tk variable below are dependent, update
    // both together (saves trig hard coding it).
    var swFactor = type == mxConstants.ARROW_DIAMOND ? 0.7071 : 0.9862;
    var endOffsetX = unitX * sw * swFactor;
    var endOffsetY = unitY * sw * swFactor;

    unitX = unitX * (size + sw);
    unitY = unitY * (size + sw);

    var pt = pe.clone();
    pt.x -= endOffsetX;
    pt.y -= endOffsetY;

    pe.x += -unitX - endOffsetX;
    pe.y += -unitY - endOffsetY;

    // thickness factor for diamond
    var tk = type == mxConstants.ARROW_DIAMOND ? 2 : 3.4;

    return function () {
      canvas.begin();
      canvas.moveTo(pt.x, pt.y);
      canvas.lineTo(
        pt.x - unitX / 2 - unitY / tk,
        pt.y + unitX / tk - unitY / 2
      );
      canvas.lineTo(pt.x - unitX, pt.y - unitY);
      canvas.lineTo(
        pt.x - unitX / 2 + unitY / tk,
        pt.y - unitY / 2 - unitX / tk
      );
      canvas.close();

      if (filled) {
        canvas.fillAndStroke();
      } else {
        canvas.stroke();
      }
    };
  }

  mxMarker.addMarker("diamond", diamond);
  mxMarker.addMarker("diamondThin", diamond);
})();
